﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Linq;

namespace Gmantis.Controls.DataGrid
{
    [TemplatePart(Name = "FilterAllCheckBox", Type = typeof(CheckBox))]
    public class DataGridMultiValueFilter : ItemsControl, IDataGridFilter, IDataGridFilterUnity, INotifyPropertyChanged
    {
        // Fields
        internal CheckBox _elementFilterAllCheckBox;
        private DataGridFilterState _filter;
        internal bool _isLoaded;
        internal const string FilterAllCheckBoxElementName = "FilterAllCheckBox";
        public static readonly DependencyProperty FilterProperty;
        public static readonly DependencyProperty FocusBrushProperty;
        public static readonly DependencyProperty InputBackgroundProperty;
        public static readonly DependencyProperty InputForegroundProperty;
        public static readonly DependencyProperty ItemStyleProperty;
        public static readonly DependencyProperty MouseOverBrushProperty;
        public static readonly DependencyProperty PressedBrushProperty;
        public static readonly DependencyProperty ValueMemberPathProperty;

        // Events
        public event EventHandler<PropertyChangedEventArgs<DataGridFilterState>> FilterChanged;

        public event PropertyChangedEventHandler PropertyChanged;

        // Methods
        static DataGridMultiValueFilter()
        {
            FilterProperty = DependencyProperty.Register("filter", typeof(DataGridFilterState), typeof(DataGridMultiValueFilter), new PropertyMetadata(null, (d, a) => ((DataGridMultiValueFilter)d).RaisePropertyChanged("Filter")));
            ValueMemberPathProperty = DependencyProperty.Register("ValueMemberPath", typeof(string), typeof(DataGridMultiValueFilter), new PropertyMetadata(""));
            ItemStyleProperty = DependencyProperty.Register("ItemStyle", typeof(Style), typeof(DataGridMultiValueFilter), null);
            MouseOverBrushProperty = DependencyProperty.Register("MouseOverBrush", typeof(Brush), typeof(DataGridMultiValueFilter), null);
            PressedBrushProperty = DependencyProperty.Register("PressedBrush", typeof(Brush), typeof(DataGridMultiValueFilter), null);
            InputBackgroundProperty = DependencyProperty.Register("InputBackground", typeof(Brush), typeof(DataGridMultiValueFilter), null);
            InputForegroundProperty = DependencyProperty.Register("InputForeground", typeof(Brush), typeof(DataGridMultiValueFilter), null);
            FocusBrushProperty = DependencyProperty.Register("FocusBrush", typeof(Brush), typeof(DataGridMultiValueFilter), null);
        }

        public DataGridMultiValueFilter()
        {
            base.DefaultStyleKey = typeof(DataGridMultiValueFilter);
        }

        public void Clear()
        {
            if (this._isLoaded)
            {
                this._elementFilterAllCheckBox.IsChecked = true;
                DataGridFilterState state = this._filter;
                DataGridFilterState state2 = (DataGridFilterState)(this._filter = null);
                if (this.FilterChanged != null)
                {
                    PropertyChangedEventArgs<DataGridFilterState> e = new PropertyChangedEventArgs<DataGridFilterState>
                    {
                        OldValue = state,
                        NewValue = state2
                    };
                    this.FilterChanged(this, e);
                }
            }
        }

        protected override void ClearContainerForItemOverride(DependencyObject element, object item)
        {
            ToggleButton button = element as ToggleButton;
            button.Content = null;
            button.ContentTemplate = null;
            button.ClearValue(ToggleButton.IsCheckedProperty);
            button.ClearValue(Control.ForegroundProperty);
            button.Style = null;
        }

        public void Create()
        {
            DataGridFilterState state = this._filter;
            this._filter = this.Filter;
            if (this.FilterChanged != null)
            {
                PropertyChangedEventArgs<DataGridFilterState> e = new PropertyChangedEventArgs<DataGridFilterState>
                {
                    OldValue = state,
                    NewValue = this._filter
                };
                this.FilterChanged(this, e);
            }
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new CheckBox();
        }

        private T GetTemplateChild<T>(string childName, bool required, ref string errors) where T : class
        {
            DependencyObject templateChild = base.GetTemplateChild(childName);
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "template part", childName, templateChild, required, ref errors);
            return (templateChild as T);
        }

        private static Storyboard GetTemplateChildResource(FrameworkElement root, string resourceName, bool required, ref string errors)
        {
            return GetTemplateChildResource<Storyboard>(root, resourceName, required, ref errors);
        }

        private static T GetTemplateChildResource<T>(FrameworkElement root, string resourceName, bool required, ref string errors) where T : class
        {
            object child = root.Resources[resourceName];
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "resource", resourceName, child, required, ref errors);
            return (child as T);
        }

        private void InitializeFilterAllCheckBoxPart()
        {
            Binding binding = new Binding
            {
                Mode = BindingMode.TwoWay,
                Converter = new CheckBoxSelectAllConverter()
            };
            this._elementFilterAllCheckBox.SetBinding(ToggleButton.IsCheckedProperty, binding.From<DataGridMultiValueFilter>(this, x => x.Filter));
            this._elementFilterAllCheckBox.IsThreeState = false;
        }

        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return (item is ToggleButton);
        }

        public void Load(DataGridFilterState filterState)
        {
            this.Filter = filterState;
        }

        public override void OnApplyTemplate()
        {
            string errors = string.Empty;
            base.OnApplyTemplate();
            this._isLoaded = true;
            this._elementFilterAllCheckBox = this.GetTemplateChild<CheckBox>("FilterAllCheckBox", true, ref errors);
            if (this._elementFilterAllCheckBox != null)
            {
                this.InitializeFilterAllCheckBoxPart();
            }
            if (!string.IsNullOrEmpty(errors))
            {
                this._isLoaded = false;
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Template cannot be applied to DataGridMultiValueFilter.\nDetails: {0}", new object[] { errors }));
                }
            }
        }

        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            ToggleButton target = element as ToggleButton;
            Binding binding = new Binding
            {
                Mode = BindingMode.TwoWay,
                Converter = new ToggleButtonListItemConverter(this, item)
            };
            target.SetBinding(ToggleButton.IsCheckedProperty, binding.From<DataGridMultiValueFilter>(this, x => x.Filter));
            if (this.ItemStyle != null)
            {
                target.Style = this.ItemStyle;
            }
            target.SetBinding<DataGridMultiValueFilter>(Control.ForegroundProperty, this, x => x.InputForeground);
        }

        protected internal void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public void SetIsVirtualizing(bool isVirtualized)
        {
            if (isVirtualized)
            {
                base.ItemsPanel = PlatformIndependent.LoadXaml<ItemsPanelTemplate>("<ItemsPanelTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"><VirtualizingStackPanel Background='Transparent'/></ItemsPanelTemplate>");
            }
            else
            {
                base.ClearValue(ItemsControl.ItemsPanelProperty);
            }
        }

        // Properties
        public DataGridFilterState Filter
        {
            get
            {
                return (DataGridFilterState)base.GetValue(FilterProperty);
            }
            set
            {
                base.SetValue(FilterProperty, value);
            }
        }

        public Brush FocusBrush
        {
            get
            {
                return (Brush)base.GetValue(FocusBrushProperty);
            }
            set
            {
                base.SetValue(FocusBrushProperty, value);
            }
        }

        public Brush InputBackground
        {
            get
            {
                return (Brush)base.GetValue(InputBackgroundProperty);
            }
            set
            {
                base.SetValue(InputBackgroundProperty, value);
            }
        }

        public Brush InputForeground
        {
            get
            {
                return (Brush)base.GetValue(InputForegroundProperty);
            }
            set
            {
                base.SetValue(InputForegroundProperty, value);
            }
        }

        public Style ItemStyle
        {
            get
            {
                return (Style)base.GetValue(ItemStyleProperty);
            }
            set
            {
                base.SetValue(ItemStyleProperty, value);
            }
        }

        public Brush MouseOverBrush
        {
            get
            {
                return (Brush)base.GetValue(MouseOverBrushProperty);
            }
            set
            {
                base.SetValue(MouseOverBrushProperty, value);
            }
        }

        public Brush PressedBrush
        {
            get
            {
                return (Brush)base.GetValue(PressedBrushProperty);
            }
            set
            {
                base.SetValue(PressedBrushProperty, value);
            }
        }

        public string ValueMemberPath
        {
            get
            {
                return (string)base.GetValue(ValueMemberPathProperty);
            }
            set
            {
                base.SetValue(ValueMemberPathProperty, value);
            }
        }

        // Nested Types
        internal class CheckBoxSelectAllConverter : IValueConverter
        {
            // Methods
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (targetType != typeof(bool?))
                {
                    return value;
                }
                if (value == null)
                {
                    return true;
                }
                if (!(value is DataGridFilterState))
                {
                    return value;
                }
                DataGridFilterInfo firstFilterInfo = this.GetFirstFilterInfo((DataGridFilterState)value);
                if ((firstFilterInfo == null) || (firstFilterInfo.FilterOperation == DataGridFilterOperation.All))
                {
                    return true;
                }
                if (firstFilterInfo.FilterOperation == DataGridFilterOperation.None)
                {
                    return false;
                }
                return ((firstFilterInfo.FilterOperation != DataGridFilterOperation.IsOneOf) && (firstFilterInfo.FilterOperation != DataGridFilterOperation.Equal));
            }

            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (targetType == typeof(DataGridFilterState))
                {
                    if ((value == null) || ((value is bool) && !((bool)value)))
                    {
                        DataGridFilterState state = new DataGridFilterState();
                        List<DataGridFilterInfo> list = new List<DataGridFilterInfo>();
                        DataGridFilterInfo item = new DataGridFilterInfo
                        {
                            FilterType = DataGridFilterType.MultiValue,
                            FilterOperation = DataGridFilterOperation.None
                        };
                        list.Add(item);
                        state.FilterInfo = list;
                        return state;
                    }
                    if ((value is bool) && ((bool)value))
                    {
                        DataGridFilterState state2 = new DataGridFilterState();
                        List<DataGridFilterInfo> list2 = new List<DataGridFilterInfo>();
                        DataGridFilterInfo info2 = new DataGridFilterInfo
                        {
                            FilterType = DataGridFilterType.MultiValue,
                            FilterOperation = DataGridFilterOperation.All
                        };
                        list2.Add(info2);
                        state2.FilterInfo = list2;
                        return state2;
                    }
                }
                return value;
            }

            private DataGridFilterInfo GetFirstFilterInfo(DataGridFilterState filter)
            {
                if (((filter != null) && (filter.FilterInfo != null)) && (filter.FilterInfo.Count == 1))
                {
                    return filter.FilterInfo[0];
                }
                return null;
            }
        }

        internal class ToggleButtonListItemConverter : IValueConverter
        {
            // Methods
            public ToggleButtonListItemConverter(DataGridMultiValueFilter filter, object item)
            {
                this.Filter = filter;
                this.Item = item;
            }

            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value != null)
                {
                    if (!(value is DataGridFilterState))
                    {
                        return value;
                    }
                    DataGridFilterInfo firstFilterInfo = this.GetFirstFilterInfo((DataGridFilterState)value);
                    if (firstFilterInfo == null)
                    {
                        return true;
                    }
                    if (firstFilterInfo.FilterOperation == DataGridFilterOperation.IsOneOf)
                    {
                        return (firstFilterInfo.Value as IList).Contains(this.Item.GetPropertyValue<object>(this.Filter.ValueMemberPath));
                    }
                    if (firstFilterInfo.FilterOperation == DataGridFilterOperation.Equal)
                    {
                        object propertyValue = this.Item.GetPropertyValue<object>(this.Filter.ValueMemberPath);
                        return (((firstFilterInfo.Value == null) && (propertyValue == null)) ? ((object)1) : ((firstFilterInfo.Value == null) ? ((object)0) : ((object)firstFilterInfo.Value.Equals(propertyValue))));
                    }
                    if (firstFilterInfo.FilterOperation == DataGridFilterOperation.All)
                    {
                        return true;
                    }
                    if (firstFilterInfo.FilterOperation == DataGridFilterOperation.None)
                    {
                        return false;
                    }
                }
                return true;
            }

            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                IList list;
                Func<object, object> selector = null;
                Func<object, object> func3 = null;
                if (!(value is bool))
                {
                    return value;
                }
                Func<object, bool> predicate = null;
                DataGridFilterInfo filterInfo = (this.Filter != null) ? this.GetFirstFilterInfo(this.Filter.Filter) : null;
                if ((filterInfo != null) && (filterInfo.FilterOperation == DataGridFilterOperation.IsOneOf))
                {
                    if (this.Filter.Filter.FilterInfo[0].Value is IList)
                    {
                        list = new List<object>((this.Filter.Filter.FilterInfo[0].Value as IList).Cast<object>());
                    }
                    else
                    {
                        list = new List<object>();
                    }
                }
                else if ((filterInfo != null) && (filterInfo.FilterOperation == DataGridFilterOperation.Equal))
                {
                    if (selector == null)
                    {
                        selector = o => o.GetPropertyValue<object>(this.Filter.ValueMemberPath);
                    }
                    if (predicate == null)
                    {
                        predicate = o => ((o != null) && (filterInfo != null)) && o.Equals(filterInfo.Value);
                    }
                    object obj2 = this.Filter.ItemsSource.Cast<object>().Select<object, object>(selector).FirstOrDefault<object>(predicate);
                    if (obj2 != null)
                    {
                        list = new List<object> {
                        obj2
                    };
                    }
                    else
                    {
                        list = new List<object>();
                    }
                }
                else if ((filterInfo != null) && (filterInfo.FilterOperation == DataGridFilterOperation.None))
                {
                    list = new List<object>();
                }
                else
                {
                    if (func3 == null)
                    {
                        func3 = o => o.GetPropertyValue<object>(this.Filter.ValueMemberPath);
                    }
                    list = this.Filter.ItemsSource.Cast<object>().Select<object, object>(func3).Distinct<object>().ToList<object>();
                }
                if ((bool)value)
                {
                    list.Add(this.Item.GetPropertyValue<object>(this.Filter.ValueMemberPath));
                }
                else
                {
                    list.Remove(this.Item.GetPropertyValue<object>(this.Filter.ValueMemberPath));
                }
                DataGridFilterState state = new DataGridFilterState();
                List<DataGridFilterInfo> list3 = new List<DataGridFilterInfo>();
                DataGridFilterInfo item = new DataGridFilterInfo
                {
                    FilterType = DataGridFilterType.MultiValue,
                    FilterOperation = DataGridFilterOperation.IsOneOf,
                    Value = list
                };
                list3.Add(item);
                state.FilterInfo = list3;
                return state;
            }

            private DataGridFilterInfo GetFirstFilterInfo(DataGridFilterState Filter)
            {
                if (((Filter != null) && (Filter.FilterInfo != null)) && (Filter.FilterInfo.Count == 1))
                {
                    return Filter.FilterInfo[0];
                }
                return null;
            }

            // Properties
            private DataGridMultiValueFilter Filter { get; set; }

            private object Item { get; set; }
        }
    }
}
